package com.neusoft.neuiotms.dcam.fixed.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.NumberFormat;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.dto.result.PageResultDTO;
import com.neusoft.bizcore.web.dto.result.ResultDTO;
import com.neusoft.bizcore.web.dto.result.ResultListDTO;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.common.dto.AuditLogDTO;
import com.neusoft.neuiotms.common.service.AuditLogService;
import com.neusoft.neuiotms.dcam.common.dto.DcamInstitutionsDTO;
import com.neusoft.neuiotms.dcam.fixed.asynchronous.AsyncCallService;
import com.neusoft.neuiotms.dcam.fixed.converter.AssetLifeCycleConverter;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetAttachmentDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetLifeCycleDTO;
import com.neusoft.neuiotms.dcam.fixed.model.AssetAttachment;
import com.neusoft.neuiotms.dcam.fixed.model.AssetLifeCycle;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetAttachmentRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetLifeCycleRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.service.AssetService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

@Api(tags = "资产管理")
@RestController
@RequestMapping(value = "/api/w/fixedAsset")
@Slf4j
public class AssetController {

    @Autowired
    private AssetService assetService;
    @Autowired
    private AsyncCallService asyncCallService;
    @Autowired
    private AuditLogService auditLogService;
    @Autowired
    private AssetAttachmentRepository assetAttachmentRepository;
    @Autowired
    private AssetLifeCycleRepository assetLifeCycleRepository;
    @Autowired
    private AssetLifeCycleConverter assetLifeCycleConverter;
    @Autowired
    private AssetRepository assetRepository;

    @ApiOperation("查询所有资产")
    @GetMapping
    public ResultListDTO<AssetDTO> index(final Searchable searchable, final UserBean userBean) {
        final List<AssetDTO> DTOs = this.assetService.indexAll(searchable, userBean);
        final ResultListDTO<AssetDTO> result = ResultListDTO.success(DTOs);
        return result;
    }

    @ApiOperation("分页查询所有资产")
    @GetMapping("/p")
    public PageResultDTO<AssetDTO> search(final Pageable pageable, final Searchable searchable, final UserBean userBean)
            throws FileNotFoundException {
        return PageResultDTO.success(this.assetService.search(pageable, searchable, userBean));
    }

    @ApiOperation("创建资产")
    @PostMapping
    public ResultDTO<AssetDTO> create(@RequestBody final AssetDTO dto, HttpServletRequest request, UserBean userBean) {
        final AssetDTO result = this.assetService.create(dto);
        final AuditLogDTO log = new AuditLogDTO();
        log.setUser(userBean.getName());
        log.setRemoteIp(request.getHeader("x-forwarded-for") == null
                ? request.getRemoteAddr() : request.getHeader("x-forwarded-for"));
        log.setModule("资产管理");
        log.setOpType("创建");
        log.setOpText("创建一条资产");
        this.auditLogService.create(log);
        return ResultDTO.success(result);
    }

    @ApiOperation(value = "修改资产")
    @PutMapping("/{id}")
    public ResultDTO<AssetDTO> update(@PathVariable final Long id,
            @RequestBody final AssetDTO dto) {
        final AssetDTO result = this.assetService.update(id, dto);
        return ResultDTO.success(result);
    }

    @ApiOperation("资产详情")
    @GetMapping("/{id}")
    public ResultDTO<AssetDTO> details(@PathVariable final Long id) {
        final AssetDTO dto = this.assetService.details(id);
        return ResultDTO.success(dto);
    }

    @ApiOperation("获取单位")
    @GetMapping("/insititutions")
    public List<DcamInstitutionsDTO> getInsititutions(UserBean userBean) {
        return this.assetService.searchInstitution(userBean);
    }

    @ApiOperation("删除资产")
    @DeleteMapping("/{id}")
    public ResultDTO<Void> delete(@PathVariable final Long id) {
        this.assetService.delete(id);
        return ResultDTO.success();
    }

    @ApiOperation("删除资产")
    @DeleteMapping("/batch/{ids}")
    public ResultDTO<Void> deleteBatch(@PathVariable final Long[] ids) {
        this.assetService.deleteBatch(ids);
        return ResultDTO.success();
    }

    @ApiOperation("处置资产")
    @DeleteMapping("/batchHandles/{ids}")
    public ResultDTO<Void> batchHandles(@PathVariable final Long[] ids) {
        this.assetService.batchHandles(ids);
        return ResultDTO.success();
    }

    @ApiOperation("生命周期管理")
    @PutMapping("/batchHandles/{ids}/{status}")
    public ResultDTO<Void> lifeCycle(@PathVariable final Long[] ids, @PathVariable String status) {
        this.assetService.lifeCycle(ids, status);
        return ResultDTO.success();
    }

    @ApiOperation("导出二维码")
    @GetMapping("/qrcode/{ids}")
    public void download(@PathVariable final Long[] ids, final HttpServletResponse response) {
        OutputStream stream = null;
        try {
            stream = response.getOutputStream();
            final String path = this.assetService.qrcodeFile(ids);
            // path是指欲下载的文件的路径。
            final File file = new File(path);
            // 取得文件名。
            final String filename = file.getName();
            // 取得文件的后缀名。
            // String suffix = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
            // 以流的形式下载文件。
            final InputStream fis = new BufferedInputStream(new FileInputStream(path));
            final byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
            response.addHeader("Content-Length", "" + file.length());
            stream = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            stream.write(buffer);
            stream.flush();
            stream.close();

        } catch (final Exception e) {
            AssetController.log.error("下载二维码失败", e);
        } finally {
            try {
                stream.close();
            } catch (final IOException e) {
                AssetController.log.error("关闭输入流失败", e);
            }
        }
    }

    @ApiOperation("下载模板")
    @GetMapping("/template")
    public void template(final HttpServletResponse response, UserBean userBean) {
        final Workbook workbook = this.assetService.template(userBean);
        if (workbook == null) {
            AssetController.log.error("模板导出失败");
        }
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition",
                    String.format("attachment; filename=%s",
                            URLEncoder.encode("资产导入模板" + ".xlsx", "UTF-8")));
            workbook.write(out);
            out.flush();
        } catch (final Exception e) {
            AssetController.log.error("下载模板失败", e);
        } finally {
            try {
                out.close();
            } catch (final IOException e) {
                AssetController.log.error("下载模板关闭输出流失败", e);
            }
        }
    }

    @ApiOperation("导入资产")
    @PostMapping("/import")
    public void upload(@RequestParam("file") final MultipartFile file, HttpServletRequest request,
            final UserBean userBean) {
        AssetController.log.info("资产导入----controller");
        try {
            final InputStream fileStream = file.getInputStream();
            final Callable<String> callable = () -> {
                if (fileStream != null) {
                    AssetController.this.assetService.upload(fileStream, userBean.getUsername());

                    final AuditLogDTO log = new AuditLogDTO();
                    log.setUser(userBean.getName());
                    log.setRemoteIp(request.getHeader("x-forwarded-for") == null
                            ? request.getRemoteAddr() : request.getHeader("x-forwarded-for"));
                    log.setModule("资产管理");
                    log.setOpType("导入");
                    log.setOpText("导入资产成功");
                    this.auditLogService.create(log);
                }
                return null;
            };
            this.asyncCallService.handle(callable);
        } catch (final IOException e) {
            AssetController.log.error(e.getMessage(), e);
        }
    }

    @ApiOperation("导出资产")
    @GetMapping(value = "/export")
    public void download(HttpServletRequest request, final Searchable searchable, final Pageable pageable,
            UserBean userBean,
            final HttpServletResponse response) {

        final Workbook workbook = this.assetService.export(searchable, pageable, userBean);
        final AuditLogDTO log = new AuditLogDTO();
        log.setUser(userBean.getName());
        log.setRemoteIp(request.getHeader("x-forwarded-for") == null
                ? request.getRemoteAddr() : request.getHeader("x-forwarded-for"));
        log.setModule("资产管理");
        log.setOpType("导出");
        log.setOpText("导出资产成功");
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition",
                    String.format("attachment; filename=%s",
                            URLEncoder.encode("资产导出" + LocalDateTime.now() + ".xlsx", "UTF-8")));
            workbook.write(out);
            out.flush();
        } catch (final Exception e) {
            AssetController.log.error("资产导出失败", e);
        } finally {
            try {
                out.close();
            } catch (final IOException e) {
                AssetController.log.error("资产导出关闭流失败", e);
            }
        }
    }

    @ApiOperation("查询资产数量")
    @GetMapping("/count")
    public ResultDTO<Long> count(final Searchable searchable) {
        final Long count = this.assetService.count(searchable);
        return ResultDTO.success(count);
    }

    @ApiOperation("资产净值统计报表")
    @GetMapping("/stats/report")
    public PageResultDTO<?> reportStats(final Pageable pageable, final Searchable searchable) {
        final Page<AssetDTO> result = this.assetService.search(pageable, searchable);
        final NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(2);
        nf.setMinimumFractionDigits(2);
        result.get().forEach(asset -> {
            Date useDate = asset.getUsedate();
            if (null == useDate) {
                useDate = new Date();
            }
            useDate = DateUtils.round(useDate, Calendar.MONTH);
            final Date currentMonth = DateUtils.round(new Date(), Calendar.MONTH);
            final Calendar cal1 = Calendar.getInstance();
            cal1.setTime(useDate);
            final Calendar cal2 = Calendar.getInstance();
            cal2.setTime(currentMonth);

            final int duration = (((cal2.get(Calendar.YEAR) - cal1.get(Calendar.YEAR)) * 12) + cal2.get(Calendar.MONTH))
                    - cal1.get(Calendar.MONTH);

            Double month = asset.getMonth();
            if ((null == month) || (month == 0)) {
                month = 1.0;
            }
            Double money = asset.getMoney();
            if (null == money) {
                money = 0.0;
            }

            Double availableValue = money - ((money / month) * duration);
            if (availableValue < 0) {
                availableValue = 0.0;
            }
            asset.setExt5(nf
                    .format((new BigDecimal(availableValue)).setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue()));

        });
        return PageResultDTO.success(result);
    }

    @ApiOperation("导出资产净值")
    @GetMapping(value = "/stats/export")
    public void exportStats(final Searchable searchable, final HttpServletResponse response) {

        final Workbook workbook = this.assetService.exportReport(searchable);
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition",
                    String.format("attachment; filename=%s",
                            URLEncoder.encode("资产净值统计报表导出" + LocalDateTime.now() + ".xlsx", "UTF-8")));
            workbook.write(out);
            out.flush();
        } catch (final Exception e) {
            AssetController.log.error("资产净值统计报表导出失败", e);
        } finally {
            try {
                out.close();
            } catch (final IOException e) {
                AssetController.log.error("资产净值统计报表关闭流失败", e);
            }
        }
    }

    @ApiOperation("维保到期统计报表")
    @GetMapping("/stats/maintenance/report")
    public PageResultDTO<?> maintenanceReportStats(final Pageable pageable, final Searchable searchable) {
        final Page<AssetDTO> result = this.assetService.search(pageable, searchable);
        return PageResultDTO.success(result);
    }

    @ApiOperation("导出维保到期统计")
    @GetMapping(value = "/stats/maintenance/export")
    public void maintenanceExportStats(final Searchable searchable, final HttpServletResponse response) {

        final Workbook workbook = this.assetService.exportMaintenanceReport(searchable);
        OutputStream out = null;
        try {
            out = response.getOutputStream();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition",
                    String.format("attachment; filename=%s",
                            URLEncoder.encode("维保到期统计报表导出" + LocalDateTime.now() + ".xlsx", "UTF-8")));
            workbook.write(out);
            out.flush();
        } catch (final Exception e) {
            AssetController.log.error("维保到期统计报表导出失败", e);
        } finally {
            try {
                out.close();
            } catch (final IOException e) {
                AssetController.log.error("维保到期统计报表关闭流失败", e);
            }
        }
    }

    @ApiOperation(value = "更新资产在线状态")
    @PutMapping("/update/runningstatus")
    public ResultDTO<?> update(@RequestParam final boolean status,
            @RequestParam final Long[] idArray) {
        final boolean result = this.assetService.updateAssetRunningStatus(status, idArray);
        return ResultDTO.success(result);
    }

    @ApiOperation("上传附件")
    @PutMapping("/attach")
    public ResultDTO<Void> attach(@RequestBody AssetAttachmentDTO dto) {
        this.assetService.addAttachment(dto);
        return ResultDTO.success();
    }

    @ApiOperation("查看附件")
    @GetMapping("/attach/{assetId}")
    public ResultDTO<?> attach(@PathVariable final Long assetId) {
        final AssetAttachment model = this.assetAttachmentRepository.findByAssetId(assetId);
        if (null != model) {
            final AssetAttachmentDTO dto = new AssetAttachmentDTO();
            dto.setId(model.getId());
            dto.setDescription(model.getDescription());
            dto.setAttachment(model.getAttachment());
            dto.setAssetId(assetId);

            return ResultDTO.success(dto);
        }
        return ResultDTO.success();
    }

    @ApiOperation("分页查询所有资产")
    @GetMapping("/lifecycle/p")
    public PageResultDTO<AssetLifeCycleDTO> lifecycle(final Pageable pageable, final Searchable searchable)
            throws FileNotFoundException {
        Page<AssetLifeCycle> p = this.assetLifeCycleRepository.search(pageable, searchable);
        Page<AssetLifeCycleDTO> d = this.assetLifeCycleConverter.toPageDTO(p);
        return PageResultDTO.success(d);
    }

    @ApiOperation("按资产分类统计")
    @GetMapping("/statsByType")
    public ResultListDTO<?> statsByType() {
        final List<Map<String, Object>> list = this.assetRepository.statsByType();
        return ResultListDTO.success(list);
    }
    
    @ApiOperation("按厅局统计")
    @GetMapping("/statsByInstitution")
    public ResultListDTO<?> statsByInstitution() {
        final List<Map<String, Object>> list = this.assetRepository.statsByInstitution();
        return ResultListDTO.success(list);
    }
    
    @ApiOperation("按状态统计")
    @GetMapping("/statsByStatus")
    public ResultListDTO<?> statsByStatus() {
        final List<Map<String, Object>> list = this.assetRepository.statsByStatus();
        return ResultListDTO.success(list);
    }

}
